
'''
Created on Oct 9, 2011

@author: solagna
'''
import pickle
import bdiiList
import WebDownloader.webPage
import json

class avCalc(object):
    '''
    classdocs
    '''
    __month__ = 0
    __days__ = [999,31,28,31,30,31,30,31,31,30,31,30,31] # Days of the month
    __bdiiHourAv__ = {} # format: {"bdii":{"05T06":"1.00"},{...}}
    __bdiiHourRe__ = {} 
    __bdiiMontAv__ = {}
    __bdiiMontRe__ = {}
    __bdiis__ = bdiiList.bdiiList()
    __samURL__       = "http://mon.egi.eu/myegi/sam-pi/service_availability_in_profile?vo_name=ops&profile_name=ROC&start_time=2015-%02d-01T00:00:00Z&end_time=2015-%02d-%02dT00:00:00Z&type=MONTHLY&service_flavour=Top-BDII&service_hostname=%s&output=JSON" #URL for the SAM PI (to be filled with parameters)
    __samURLhourly__ = "http://mon.egi.eu/myegi/sam-pi/service_availability_in_profile?vo_name=ops&profile_name=ROC&start_time=2015-%02d-01T00:00:00Z&end_time=2015-%02d-%02dT00:00:00Z&type=HOURLY&service_flavour=Top-BDII&service_hostname=%s&output=JSON"
    def __init__(self, month):
        '''
        Constructor
        '''
        # File names for the data output files.
        dump_h_name = "aval_h_%02d_15.pickle"%month
        dump_m_name = "aval_m_%02d_15.pickle"%month
        dump_hr_name = "aval_hr_%02d_15.pickle"%month
        dump_mr_name = "aval_mr_%02d_15.pickle"%month

        
        #Populate bdii list.
        bdii_list = self.__bdiis__.returnAllBDII()
        self.__month__ = month
        #If a dump available, for monhtly availabilities of the month, load it
        try:
            m_file = open(dump_m_name, 'r')
            m_filer= open(dump_mr_name, 'r')
            self.__bdiiMontAv__ = pickle.load(m_file)
            self.__bdiiMontRe__ = pickle.load(m_filer)
            print "Warning monthly availabilities/reliabilities not fresh!"
            m_file.close()
            m_filer.close()
        except:
            print "Getting fresh monthly data!"      
            self.populateMonthBDII()
        
        #If a dump available, for hourly availabilities of the month, load it
        try:
            h_file = open(dump_h_name, 'r')
            self.__bdiiHourAv__  = pickle.load(h_file)
            hr_file = open(dump_hr_name, 'r')
            self.__bdiiHourRe__  = pickle.load(hr_file)
            print "Warning hourly availabilities not fresh!"
            h_file.close()
            hr_file.close()
        except:
            print "Getting fresh monthly data!"      
            self.populateHourBDII() 
        
        #SERIALIZE the OBJECTs
        h_file = open(dump_h_name, 'w')
        m_file = open(dump_m_name, 'w')
        pickle.dump(self.__bdiiHourAv__,h_file)
        pickle.dump(self.__bdiiMontAv__,m_file)
        hr_file = open(dump_hr_name, 'w')
        mr_file = open(dump_mr_name, 'w')
        pickle.dump(self.__bdiiHourRe__,hr_file)
        pickle.dump(self.__bdiiMontRe__,mr_file)
        hr_file.close()
        mr_file.close()
        
    def getMonth(self):
        return self.__month__
        
    def getMonthBDII (self, bdii):
        return self.__bdiiMontAv__[bdii]
    
    
    def searchMonthBDII(self,bdii):
        url = self.buildMonthURL(self.__month__,bdii)
        wPage = WebDownloader.webPage.webPage(url)
        data = json.loads(wPage.getBody())
        bdii = data[0]["services"][0]['hostname']
        try:
            aval = data[0]['services'][0]['availabilities'][0]['availability']
            relia = data[0]['services'][0]['availabilities'][0]['reliability']
        except:
            relia = 0
            aval = 0  
        return (bdii,aval, relia)
    
    def searchHourlyBDII(self,bdii):
        aval = {}
        relia = {}
        url = self.buildHourURL(self.__month__, bdii)
        wPage = WebDownloader.webPage.webPage(url)
        data = json.loads(wPage.getBody())
        bdii = data[0]["services"][0]['hostname']
        for single_av in data[0]['services'][0]['availabilities']:
            time = single_av['timestamp']
            av_h = float(single_av['availability'])
            re_h = float(single_av['reliability'])
            maint_h = float(single_av['maintenance'])
            if re_h == -1 and maint_h == 1:
                    re_h = 1
            ttoken = time[8:13]
            aval[ttoken] = av_h
            relia[ttoken] = re_h
        return (bdii,aval, relia)
    
    def buildMonthURL (self,month,bdii):
        day = self.__days__[month]
        return self.__samURL__%(month,month,day,bdii)
    def buildHourURL (self,month,bdii):
        day = self.__days__[month]
        return self.__samURLhourly__%(month,month,day,bdii)
    
    def populateMonthBDII(self):
        for bdii in self.__bdiis__.returnAllBDII():
            try:
                (bdii_out,a_m, r_m) = self.searchMonthBDII(bdii)
                self.__bdiiMontAv__[bdii_out] = float(a_m)
                self.__bdiiMontRe__[bdii_out] = float(r_m)
            except:
                print "No availabilities for bdii: "+bdii
                self.__bdiiMontAv__[bdii] = -1
                
   
    def populateHourBDII(self):
        for ngi in self.__bdiis__.returnAllNGIs():
            ngi_list = self.__bdiis__.returnNgiBDII(ngi)
            if len(ngi_list) > 1:
                print "Populating bdiis h_avail for NGI:"+ngi
                # The NGI has more than one BDII, hourly availability needed.
                for a_bdii in ngi_list:
                    try:
                        (bdii,aval,rel) = self.searchHourlyBDII(a_bdii)
                        self.__bdiiHourAv__[bdii]=aval
                        self.__bdiiHourRe__[bdii]=rel
                    except:
                        self.__bdiiHourAv__[a_bdii]= -1
                        self.__bdiiHourRe__[a_bdii]= -1
                        
    
    
    def calculateNGIhourly(self, ngi_name):
    	'''
    		Procedure to calculate the availability of NGIs with more than one top-bdii. The availabilities of the BDIIs are ORed hour by hour.
    		NOTE: Only NGIs with more than one top-bdii in the bdiis list have hourly statistics.
    	'''
        ddbg_one = 0
        ngi_bdiis = self.__bdiis__.returnNgiBDII(ngi_name)
        unknown_hours = 0
        # Get all the keys from all the availabilities.
        list_hours = []
        for bdii_single in ngi_bdiis:
            try:
                list_hours.extend( self.__bdiiHourAv__[bdii_single].keys() )
                list_hours.extend( self.__bdiiHourRe__[bdii_single].keys() )
                print "BDII: %s has %d hours"%(bdii_single, len(self.__bdiiHourAv__[bdii_single].keys()))
            except:
                pass
        #Remove duplicates.
        list_hours = self.uniqify(list_hours)
        print "For NGI: %s, found %d hours"%(ngi_name, len(list_hours))
        #for every hour get the max availability of all the bdiis
        max_aval_hours = {}
        max_rela_hours = {}
        for hour in list_hours:
            #list_availabilities = []
            #list_reliabilities = []
            max_aval_hours[hour] = -1 #Add control value, if it's -1 at the end is being deleted.
            max_rela_hours[hour] = -1
            for bd in ngi_bdiis:
                try:
                    max_aval_hours[hour] = max(max_aval_hours[hour],self.__bdiiHourAv__[bd][hour])
                    max_rela_hours[hour] = max(max_rela_hours[hour],self.__bdiiHourRe__[bd][hour])
                except:
                    pass
            if max_aval_hours[hour] < 0:
                # Unknown aval for this hour, remove the -1 entry (to not participate to the average).
                max_aval_hours.pop(hour)
                max_rela_hours.pop(hour) #Assume that if avail is missing also relia is missing.
                unknown_hours += 1
            elif max_aval_hours[hour] < 1:
                print "For hour %s availability = %d and relia = %d"%(hour,max_aval_hours[hour],max_rela_hours[hour])
                ddbg_one += 1
            #WRONG# max_aval_hours.append(max([self.__bdiiHourAv__[bdiix][hour] for bdiix in ngi_bdiis]))
        
        #Calculate monthly availability from hours
        if (len(list_hours) - unknown_hours) > 0:
            month_av = sum(max_aval_hours.values())  / (len(list_hours) - unknown_hours)
            month_re = sum(max_rela_hours.values())  / (len(list_hours) - unknown_hours)
        else:
            month_av = -1
            month_re = -1
        print "Monthly availability for NGI: %s month %d, is: %f - with reliablity %f"%(ngi_name,self.__month__, month_av, month_re)
        print "Unknown number of hours: %d"%unknown_hours
        print "Number of hours < 1 : %d"%ddbg_one
        return (month_av, month_re)        
                
    def uniqify(self,seq): 
    	'''
    		Remove duplicates from a sequence, returning it as a list
    	'''
        # Not order preserving     
        newset = set(seq) 
        return list(newset)
     
    def calculateNGIavalRel(self, ngi_name):
        ngi_list = self.__bdiis__.returnNgiBDII(ngi_name)
        print ngi_name
        if len(ngi_list) == 1:
            try:
                return (self.__bdiiMontAv__[ngi_list[0]],self.__bdiiMontRe__[ngi_list[0]]) 
            except:
                # Exception means that there is no availability for the BDII.
                return (-1,-1)
        else:
            return self.calculateNGIhourly(ngi_name)
        
    def allNGIs (self, file_name):
        '''
            Write a csv file with availabilities for all NGIs
        '''
        f_link = open(file_name, 'w')
        f_link.write("NGI,Availability,Reliability\n")
        for ngi in self.__bdiis__.returnAllNGIs():
            (aval,reli) = self.calculateNGIavalRel(ngi)
            to_file="%s, %f, %f\n"%(ngi,aval,reli)
            f_link.write(to_file)
        f_link.close()
        
    def allBDIIsSort (self, file_name):
        '''
            Write a csv file with the availabilities (month) for all bdii sorted by ngi
        '''
        f_link = open(file_name, 'w')
        f_link.write("NGI,BDII,Availability")
        for ngi in self.__bdiis__.returnAllNGIs():
            for bdii in self.__bdiis__.returnNgiBDII(ngi):
                try:
                    aval = self.__bdiiMontAv__[bdii]
                except:
                    aval = -1 
                try:
                    relia = self.__bdiiMontRe__[bdii]
                except:
                    relia = -1
                    
                to_file="%s, %s, %f, %f\n"%(ngi,bdii,aval,relia)
                f_link.write(to_file)
        f_link.close()
    
if __name__ == "__main__":
    #Download all.
    
    av = avCalc(1) #Create the container with the availabilities for the month 'x'
    print av.__bdiiHourRe__
    av.allNGIs("availability_ngis_Jan15.csv") # Get the NGI availabilities for this month
    av.allBDIIsSort("availability_bdii_Jan15.csv") # Get the availabilitiy for the single BDII instances
    
    
